﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Services.Client;
using System.IO.IsolatedStorage;
using System.Linq;
using RentAWorker.RIA.RentAWorkerDataService;

namespace RentAWorker.RIA
{
    public class PresentationModel : INotifyPropertyChanged, IReloadPersistable
    {
		private BigDays2009Entities DataServiceContext { get; set; }

        public PresentationModel()
        {
			// Create service context (reused throught lifetime of the object)
            var serviceUri = new Uri("Data/RentAWorkerDataService.svc", UriKind.Relative);
            this.DataServiceContext = new BigDays2009Entities(serviceUri);
            this.DataServiceContext.MergeOption = MergeOption.PreserveChanges;

			// Get workers and machine types from server
            DataServiceQuery<RentResource> query = this.DataServiceContext.RentResource.Expand("Location");
            query.BeginExecute(Worker_Loaded, query);
            this.DataServiceContext.MachineType.BeginExecute(MachineTypes_Loaded, this.DataServiceContext.MachineType);

			// Default value for selected date is today
            this.SelectedDate = DateTime.Today;

			// Handle property changes (for refreshing collection of rental service objects)
            this.PropertyChanged += PresentationModel_PropertyChanged;
        }

        private void PresentationModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
			// If selected date or selected machine type has changed, reload list
			// of renatal service objects
            switch (e.PropertyName)
            {
                case "SelectedDate":
                case "SelectedMachineType":
                    RefreshRentalServiceList();
                    break;
                default:
                    break;
            }
		}

		private void RefreshRentalServiceList()
		{
            if (this.SelectedMachineType != null)
            {
                // User service operation to get rent rental service objects
                var queryUriString = String.Format(
                    "GetRentals?machineTypeId={0}&date='{1}'&$expand=RentResource",
                    this.SelectedMachineType.MachineTypeID,
                    this.SelectedDate.ToString("s"));

                this.DataServiceContext.BeginExecute<RentalService>(
                    new Uri(queryUriString, UriKind.Relative),
                    RentalServices_Loaded, this.DataServiceContext);
            }
		}

		#region Handler functions for async REST calls
		private void MachineTypes_Loaded(IAsyncResult result)
        {
            var ctx = (DataServiceQuery<MachineType>)result.AsyncState;
			this.MachineTypeList = ctx.EndExecute(result).ToList();
        }

        private void Worker_Loaded(IAsyncResult result)
        {
            var ctx = (DataServiceQuery<RentResource>)result.AsyncState;
			// Note filter based on inheritance relationship between RentResource
			// and Worker.
			this.WorkerList = ctx.EndExecute(result).ToList().OfType<Worker>();
		}

		private void RentalServices_Loaded(IAsyncResult result)
		{
			var ctx = result.AsyncState as DataServiceContext;
			this.RentalServiceList = ctx.EndExecute<RentalService>(result).ToList();

			this.GroupedRentalServiceList =
				(from s in this.RentalServiceList
				 group s by s.RentResource into sGrouped
				 select new KeyValuePair<RentResource, IEnumerable<RentalService>>(
					sGrouped.Key,
					sGrouped)).ToList();
		}
		#endregion

		#region Helper functions for persisting object state
		public void OnPersist(IsolatedStorageSettings settings)
        {
			if (this.SelectedMachineType != null)
			{
				// Clear Resources, to reduce memory set in Isolated storage
				this.SelectedMachineType.RentResources.Clear();
				settings["SelectedMachineType"] = this.SelectedMachineType;
			}

			settings["SelectedDate"] = this.SelectedDate.Date;
		}

        public void OnUnPersist(IsolatedStorageSettings settings)
        {
            if (settings.Contains("SelectedDate") && settings.Contains("SelectedMachineType"))
            {
                this.SelectedDate = (DateTime)settings["SelectedDate"];
                this.SelectedMachineType = (MachineType)settings["SelectedMachineType"];

                this.RefreshRentalServiceList();
            }
		}
		#endregion

        #region Bindable Properties
		private IEnumerable<Worker> _workerList = default(IEnumerable<Worker>);
        public IEnumerable<Worker> WorkerList
        {
            get
            {
                return _workerList;
            }
            private set
            {
                _workerList = value;
                OnPropertyChanged("WorkerList");
            }
        }

		private IEnumerable<RentalService> _rentalServiceList = default(IEnumerable<RentalService>);
		public IEnumerable<RentalService> RentalServiceList
        {
            get
            {
				return _rentalServiceList;
            }
            private set
            {
				_rentalServiceList = value;
				OnPropertyChanged("RentalServiceList");
			}
        }

		private IEnumerable<KeyValuePair<RentResource, IEnumerable<RentalService>>> _groupedRentalServiceList =
			default(IEnumerable<KeyValuePair<RentResource, IEnumerable<RentalService>>>);
		public IEnumerable<KeyValuePair<RentResource, IEnumerable<RentalService>>> GroupedRentalServiceList
		{
			get
			{
				return _groupedRentalServiceList;
			}
			private set
			{
				_groupedRentalServiceList = value;
				OnPropertyChanged("GroupedRentalServiceList");
			}
		}

		private IEnumerable<MachineType> _machineTypeList = default(IEnumerable<MachineType>);
		public IEnumerable<MachineType> MachineTypeList
		{
			get
			{
				return _machineTypeList;
			}
			set
			{
				_machineTypeList = value;
				OnPropertyChanged("MachineTypeList");
			}
		}

        private DateTime _selectedDate = default(DateTime);
        public DateTime SelectedDate
        {
            get
            {
                return _selectedDate;
            }
            set
            {
                _selectedDate = value;
                OnPropertyChanged("SelectedDate");
            }
        }

        private MachineType _selectedMachineType = default(MachineType);
        public MachineType SelectedMachineType
        {
            get
            {
                return _selectedMachineType;
            }
            set
            {
                _selectedMachineType = value;
                OnPropertyChanged("SelectedMachineType");
            }
        }
        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}